/*********************************************************************************
 *Copyright:  (C) 2018 LingYun IoT System Studio
 *Author:  Guo Wenxue <guowenxue@gmail.com>
 *Copied by whut_zty <zhuty_cn@163.com>
 *Temperature and humidity sensor driver file.
 *Created in 20210113
 ********************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <sys/stat.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <errno.h>
#include <string.h>

#define SOFTRESET 0xFE
#define TRIGGER_TEMPERATURE_NO_HOLD 0xF3
#define TRIGGER_HUMIDITY_NO_HOLD 0xF5
//#define I2C_API_IOCTL /* Use I2C userspace driver ioctl API */
#define I2C_API_RDWR /* Use I2C userspace driver read/write API */

static inline void msleep(unsigned long ms);
static inline void dump_buf(const char *prompt, uint8_t *buf, int size);

int sht2x_init(void);
int sht2x_softreset(int fd);
int sht2x_get_serialnumber(int fd, uint8_t *serialnumber, int size);
int sht2x_get_temp_humidity(int fd, float *temp, float *rh);
void *OutputData(char *buf, int size)
{
    int fd;
    float temp;
    float rh;
    uint8_t serialnumber[8];
    fd = sht2x_init();
    if (fd < 0)
    {
        printf("SHT2x initialize failure\n");
        
    }
    if (sht2x_softreset(fd) < 0)
    {
        printf("SHT2x softreset failure\n");
        
    }
    if (sht2x_get_serialnumber(fd, serialnumber, 8) < 0)
    {
        printf("SHT2x get serial number failure\n");
        
    }
    if (sht2x_get_temp_humidity(fd, &temp, &rh) < 0)
    {
        printf("SHT2x get get temperature and relative humidity failure\n");
        
    }
    printf("Temperature=%lf ¡æ relative humidity=%lf\n", temp, rh);
    snprintf(buf, size, "%lf , %lf", temp, rh);

}
static inline void msleep(unsigned long ms)
{
    struct timespec cSleep;
    unsigned long ulTmp;
    cSleep.tv_sec = ms / 1000;
    if (cSleep.tv_sec == 0)
    {
        ulTmp = ms * 10000;
        cSleep.tv_nsec = ulTmp * 100;
    }
    else
    {
        cSleep.tv_nsec = 0;
    }
    nanosleep(&cSleep, 0);
}
static inline void dump_buf(const char *prompt, uint8_t *buf, int size)
{
    int i;
    if (!buf)
    {
        return;
    }
    if (prompt)
    {
        printf("%s ", prompt);
    }
    for (i = 0; i < size; i++)
    {
        printf("%02x ", buf[i]);
    }
    printf("\n");
    return;
}
#ifdef I2C_API_RDWR /* Use I2C userspace driver read/write API */
int sht2x_init(void)
{
    int fd;
    if ((fd = open("/dev/i2c-1", O_RDWR)) < 0)
    {
        printf("i2c device open failed: %s\n", strerror(errno));
        return -1;
    }
    /* set I2C mode and SHT2x slave address */
    ioctl(fd, I2C_TENBIT, 0);   /* Not 10-bit but 7-bit mode */
    ioctl(fd, I2C_SLAVE, 0x40); /* set SHT2x slava address 0x40*/
    return fd;
}
int sht2x_softreset(int fd)
{
    uint8_t buf[4];
    if (fd < 0)
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__);
        return -1;
    }
    /* software reset SHT2x */
    memset(buf, 0, sizeof(buf));
    buf[0] = SOFTRESET;
    write(fd, buf, 1);
    msleep(50);
    return 0;
}
int sht2x_get_temp_humidity(int fd, float *temp, float *rh)
{
    uint8_t buf[4];
    if (fd < 0 || !temp || !rh)
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__);
        return -1;
    }
    /* send trigger temperature measure command and read the data */
    memset(buf, 0, sizeof(buf));
    buf[0] = TRIGGER_TEMPERATURE_NO_HOLD;
    write(fd, buf, 1);
    msleep(85); /* datasheet: typ=66, max=85 */
    memset(buf, 0, sizeof(buf));
    read(fd, buf, 3);
    dump_buf("Temperature sample data: ", buf, 3);
    *temp = 175.72 * (((((int)buf[0]) << 8) + buf[1]) / 65536.0) - 46.85;
    /* send trigger humidity measure command and read the data */
    memset(buf, 0, sizeof(buf));
    buf[0] = TRIGGER_HUMIDITY_NO_HOLD;
    write(fd, buf, 1);
    msleep(29); /* datasheet: typ=22, max=29 */
    memset(buf, 0, sizeof(buf));
    read(fd, buf, 3);
    dump_buf("Relative humidity sample data: ", buf, 3);
    *rh = 125 * (((((int)buf[0]) << 8) + buf[1]) / 65536.0) - 6;
    return 0;
}
int sht2x_get_serialnumber(int fd, uint8_t *serialnumber, int size)
{
    uint8_t buf[4];
    if (fd < 0 || !serialnumber || size != 8)
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__);
        return -1;
    }
    /* Read SerialNumber from Location 1 */
    memset(buf, 0, sizeof(buf));
    buf[0] = 0xfa; /* command for readout on-chip memory */
    buf[1] = 0x0f; /* on-chip memory address */
    write(fd, buf, 2);
    memset(buf, 0, sizeof(buf));
    read(fd, buf, 4);
    serialnumber[5] = buf[0]; /* Read SNB_3 */
    serialnumber[4] = buf[1]; /* Read SNB_2 */
    serialnumber[3] = buf[2]; /* Read SNB_1 */
    serialnumber[2] = buf[3]; /* Read SNB_0 */
    /* Read SerialNumber from Location 2 */
    memset(buf, 0, sizeof(buf));
    buf[0] = 0xfc; /* command for readout on-chip memory */
    buf[1] = 0xc9; /* on-chip memory address */
    write(fd, buf, 2);
    memset(buf, 0, sizeof(buf));
    read(fd, buf, 4);
    serialnumber[1] = buf[0]; /* Read SNC_1 */
    serialnumber[0] = buf[1]; /* Read SNC_0 */
    serialnumber[7] = buf[2]; /* Read SNA_1 */
    serialnumber[6] = buf[3]; /* Read SNA_0 */
    dump_buf("SHT2x Serial number: ", serialnumber, 8);
    return 0;
}
#elif (defined I2C_API_IOCTL) /* Use I2C userspace driver read/write API */

int sht2x_init(void)
{
    int fd;
    if ((fd = open("/dev/i2c-1", O_RDWR)) < 0)
    {
        printf("i2c device open failed: %s\n", strerror(errno));
        return -1;
    }
    return fd;
}
int sht2x_softreset(int fd)
{
    struct i2c_msg msg;
    struct i2c_rdwr_ioctl_data sht2x_data;
    uint8_t buf[2];
    if (fd < 0)
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__);
        return -1;
    }
    msg.addr = 0x40;
    msg.flags = 0; //write
    msg.len = 1;
    msg.buf = buf;
    msg.buf[0] = SOFTRESET;
    sht2x_data.nmsgs = 1;
    sht2x_data.msgs = &msg;
    if (ioctl(fd, I2C_RDWR, &sht2x_data) < 0)
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        return -2;
    }
    msleep(50);
    return 0;
}
int sht2x_get_serialnumber(int fd, uint8_t *serialnumber, int size)
{
    struct i2c_msg msgs[2];
    struct i2c_rdwr_ioctl_data sht2x_data;
    uint8_t sbuf[2];
    uint8_t rbuf[4];
    if (fd < 0)
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__);
        return -1;
    }
    /*+------------------------------------------+
    *| Read SerialNumber from Location 1 |
    *+------------------------------------------+*/
    msgs[0].addr = 0x40;
    msgs[0].flags = 0; //write
    msgs[0].len = 2;
    msgs[0].buf = sbuf;
    msgs[0].buf[0] = 0xfa; /* command for readout on-chip memory */
    msgs[0].buf[1] = 0x0f; /* on-chip memory address */
    msgs[1].addr = 0x40;
    msgs[1].flags = I2C_M_RD; //write
    msgs[1].len = 4;
    msgs[1].buf = rbuf;
    sht2x_data.nmsgs = 2;
    sht2x_data.msgs = msgs;
    if (ioctl(fd, I2C_RDWR, &sht2x_data) < 0)
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        return -2;
    }
    serialnumber[5] = rbuf[0]; /* Read SNB_3 */
    serialnumber[4] = rbuf[1]; /* Read SNB_2 */
    serialnumber[3] = rbuf[2]; /* Read SNB_1 */
    serialnumber[2] = rbuf[3]; /* Read SNB_0 */
    /*+------------------------------------------+
    *| Read SerialNumber from Location 2 |
    *+------------------------------------------+*/
    msgs[0].addr = 0x40;
    msgs[0].flags = 0; //write
    msgs[0].len = 2;
    msgs[0].buf = sbuf;
    msgs[0].buf[0] = 0xfc; /* command for readout on-chip memory */
    msgs[0].buf[1] = 0xc9; /* on-chip memory address */
    msgs[1].addr = 0x40;
    msgs[1].flags = I2C_M_RD; //write
    msgs[1].len = 4;
    msgs[1].buf = rbuf;
    sht2x_data.nmsgs = 2;
    sht2x_data.msgs = msgs;
    if (ioctl(fd, I2C_RDWR, &sht2x_data) < 0)
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        return -2;
    }
    serialnumber[1] = rbuf[0]; /* Read SNC_1 */
    serialnumber[0] = rbuf[1]; /* Read SNC_0 */
    serialnumber[7] = rbuf[2]; /* Read SNA_1 */
    serialnumber[6] = rbuf[3]; /* Read SNA_0 */
    dump_buf("SHT2x Serial number: ", serialnumber, 8);
    return 0;
}
int sht2x_get_temp_humidity(int fd, float *temp, float *rh)
{
    struct i2c_msg msg;
    struct i2c_rdwr_ioctl_data sht2x_data;
    uint8_t buf[4];
    if (fd < 0)
    {
        printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__);
        return -1;
    }
    /*+------------------------------------------+
    *| measure and get temperature |
    *+------------------------------------------+*/
    msg.addr = 0x40;
    msg.flags = 0; //write
    msg.len = 1;
    msg.buf = buf;
    msg.buf[0] = TRIGGER_TEMPERATURE_NO_HOLD; /* trigger temperature without hold I2C bus */
    sht2x_data.nmsgs = 1;
    sht2x_data.msgs = &msg;
    if (ioctl(fd, I2C_RDWR, &sht2x_data) < 0)
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        return -2;
    }
    msleep(85);
    memset(buf, 0, sizeof(buf));
    msg.addr = 0x40;
    msg.flags = I2C_M_RD; //write
    msg.len = 3;
    msg.buf = buf;
    sht2x_data.nmsgs = 1;
    sht2x_data.msgs = &msg;
    if (ioctl(fd, I2C_RDWR, &sht2x_data) < 0)
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        return -2;
    }
    //dump_buf("Temperature sample data: ", buf, 3);
    *temp = 175.72 * (((((int)buf[0]) << 8) + buf[1]) / 65536.0) - 46.85;
    /*+------------------------------------------+
    *| measure and get relative humidity |
    *+------------------------------------------+*/
    msg.addr = 0x40;
    msg.flags = 0; //write
    msg.len = 1;
    msg.buf = buf;
    msg.buf[0] = TRIGGER_HUMIDITY_NO_HOLD; /* trigger humidity without hold I2C bus */
    sht2x_data.nmsgs = 1;
    sht2x_data.msgs = &msg;
    if (ioctl(fd, I2C_RDWR, &sht2x_data) < 0)
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        return -2;
    }
    msleep(29);
    memset(buf, 0, sizeof(buf));
    msg.addr = 0x40;
    msg.flags = I2C_M_RD; //write
    msg.len = 3;
    msg.buf = buf;
    sht2x_data.nmsgs = 1;
    sht2x_data.msgs = &msg;
    if (ioctl(fd, I2C_RDWR, &sht2x_data) < 0)
    {
        printf("%s() ioctl failure: %s\n", __func__, strerror(errno));
        return -2;
    }
    //dump_buf("Relative humidity sample data: ", buf, 3);
    *rh = 125 * (((((int)buf[0]) << 8) + buf[1]) / 65536.0) - 6;
    return 0;
}
#endif

